package com.xgkj.diyiketang.util;

import android.R.integer;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

import com.xgkj.diyiketang.util.ViewUtil.Size;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ImageCache {
    private static final String TAG = "ImageCache";
    private static ImageCache mInstance;
    private Context mContext;
    private LruCache<String, Bitmap> mMemoryCache;
    private LruCache<String, Integer> mMemoryCacheimage;
    private DiskLruCache mDiskLruCache;
    private static final String CACHE = "diyiketang/cache";
    private static final int MAX_SIZE = 10 * 1024 * 1024;
    private Hashtable<String, List<ImageCallBack>> callbackMap = new Hashtable<String, List<ImageCallBack>>();
    private List<String> downList = new ArrayList<String>();
    private ExecutorService mImageThreadPool = null;

    public ImageCache(Context context) {
        mContext = context;
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 8;
//        PalLog.e(TAG, cacheSize + "缓存大小");
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };

        try {
            File cacheFile = EatShowSetting.getInstance(mContext).getDataFolder(
                    CACHE);
            if (!cacheFile.exists()) {
                cacheFile.mkdir();
            }
            mDiskLruCache = DiskLruCache.open(cacheFile,
                    getAppVersion(mContext), 1, MAX_SIZE);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static ImageCache getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new ImageCache(context);
        }
        return mInstance;
    }

    public int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), 0);
            return info.versionCode;
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    //在listView中使用时，要先判断是否有缓存，在下载，否则可能会导致list图片加载顺序出错，示例：
//	Bitmap bitmap = ImageCache.getInstance(mContext).getBitmapFromMemoryCache(imageThumbUrls[position]);
//	if(bitmap == null){
//	这里可以设置个默认图片
//	ImageCache.getInstance(mContext).loadBitmapToView(viewHolder.titleImage, imageThumbUrls[position]);
//	}else{
//		viewHolder.titleImage.setImageBitmap(bitmap);
//	}
    public void loadBitmapToView(ImageView view, String url, ViewUtil.Size size) {
        try {
            String key = size != null ? url + "&w=" + size.width + "&h=" + size.height : url;
            Bitmap bitmap = getBitmapFromMemoryCache(key);
            //|| size == null|| (size != null && bitmap.getWidth() != size.width)|| (size != null && size.height !=0 && bitmap.getHeight() != size.height)
            if (bitmap == null) {
                ImageCallBack callback = new ImageDownLoadCallback(view, url);
                if (downList.contains(url)) {
                    List<ImageCallBack> list = callbackMap.get(url);
                    if (list != null && callback != null
                            && !list.contains(callback)) {
                        list.add(callback);
                    }
                } else {
                    downList.add(url);
                    List<ImageCallBack> list = new ArrayList<ImageCallBack>();
                    list.add(callback);
                    callbackMap.put(url, list);

                    BitmapWorkerTask task = new BitmapWorkerTask(
                            new ImageCallBack() {

                                @Override
                                public void onGetImage(Bitmap bitmap, String url) {
                                    downList.remove(url);
                                    List<ImageCallBack> list = callbackMap
                                            .remove(url);
                                    if (list != null) {
                                        for (ImageCallBack callback : list) {
                                            if (callback != null) {
//												PalLog.e(TAG,bitmap.getWidth()+"**22**"+bitmap.getHeight());
                                                callback.onGetImage(bitmap, url);
                                            }
                                        }
                                    }
                                }

                                @Override
                                public void onGetError(String url) {
                                    downList.remove(url);
                                    List<ImageCallBack> list = callbackMap
                                            .remove(url);
                                    if (list != null) {
                                        for (ImageCallBack callback : list) {
                                            if (callback != null) {
                                                callback.onGetError(url);
                                            }
                                        }
                                    }
                                }
                            }, size);
                    task.executeOnExecutor(getThreadPool(), url);
                }
            } else {
                if (view != null && bitmap != null) {
                    view.setImageBitmap(bitmap);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemoryCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

    public Bitmap getBitmapFromMemoryCache(String key) {
        return mMemoryCache.get(key);
    }

    public int getBitmapFromMemoryCacheImage(String key) {
        return mMemoryCacheimage.get(key);
    }

    public String getCacheKey(String url, Size size) {
        String key = size != null ? url + "&w=" + size.width + "&h=" + size.height : url;
        return key;
    }

    public String getCacheImage(int dr, Size size) {
        String key = size != null ? dr + "" + "&w=" + size.width + "&h=" + size.height : dr + "";
        return key;
    }

    /**
     * 使用MD5算法对传入的key进行加密并返回。
     */
    public String hashKeyForDisk(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    class BitmapWorkerTask extends AsyncTask<String, integer, Bitmap> {
        private ImageCallBack mCallback;
        Size mSize;

        public BitmapWorkerTask(ImageCallBack callback, Size size) {
            mCallback = callback;
            mSize = size;
        }

        /**
         * 图片的URL地址
         */
        private String imageUrl;

        @Override
        protected Bitmap doInBackground(String... params) {
            imageUrl = params[0];
            FileDescriptor fileDescriptor = null;
            File cacheFile = null;
            FileInputStream fileInputStream = null;
            DiskLruCache.Snapshot snapShot = null;
            try {
                // 生成图片URL对应的key
                final String key = hashKeyForDisk(imageUrl);
                // 查找key对应的缓存

                if (mDiskLruCache != null)
                    snapShot = mDiskLruCache.get(key);
                if (snapShot == null) {
                    // 如果没有找到对应的缓存，则准备从网络上请求数据，并写入缓存
                    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
                    if (editor != null) {
                        OutputStream outputStream = editor.newOutputStream(0);
                        if (downloadUrlToStream(imageUrl, outputStream)) {
                            editor.commit();
                            mDiskLruCache.flush();
                        } else {
                            editor.abort();
                        }
                    }
                    // 缓存被写入后，再次查找key对应的缓存
                    snapShot = mDiskLruCache.get(key);
                }
                if (snapShot != null) {
                    fileInputStream = (FileInputStream) snapShot
                            .getInputStream(0);
                    fileDescriptor = fileInputStream.getFD();
                    cacheFile = new File(mDiskLruCache.getDirectory(), key + ".0");
                }
                // 将缓存数据解析成Bitmap对象
                Bitmap bitmap = null;
                if (fileDescriptor != null) {
                    if (mSize == null) {
//						bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
                        bitmap = createNoSizeBitmap(fileDescriptor, cacheFile);
                    } else {
                        bitmap = createBitmap(fileDescriptor, mSize, cacheFile);
                    }
                }
                if (bitmap != null) {
                    // 将Bitmap对象添加到内存缓存当中
//					PalLog.e(TAG,bitmap.getWidth()+"****"+bitmap.getHeight()+"******bitmap size:"+bitmap.getByteCount());
                    String cachekey = mSize != null ? imageUrl + "&w=" + mSize.width + "&h=" + mSize.height : imageUrl;
                    addBitmapToMemoryCache(cachekey, bitmap);
                }
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fileDescriptor == null && fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                    }
                }
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (mCallback != null) {
                if (bitmap == null) {
                    mCallback.onGetError(imageUrl);
                } else {
                    mCallback.onGetImage(bitmap, imageUrl);
                }
            }
        }

        private boolean downloadUrlToStream(String urlString,
                                            OutputStream outputStream) {
            HttpURLConnection urlConnection = null;
            BufferedOutputStream out = null;
            BufferedInputStream in = null;
            try {
                final URL url = new URL(urlString);
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setConnectTimeout(10000);
                urlConnection.setReadTimeout(10000);
                in = new BufferedInputStream(urlConnection.getInputStream(),
                        8 * 1024);
                out = new BufferedOutputStream(outputStream, 8 * 1024);
                int b;
                while ((b = in.read()) != -1) {
                    out.write(b);
                }
                return true;
            } catch (final IOException e) {
                e.printStackTrace();
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    }

    private Bitmap createBitmap(FileDescriptor filepath, Size size, File file) throws Exception {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inPurgeable = true;
        options.inInputShareable = true;
        BitmapFactory.decodeFileDescriptor(filepath, null, options);

        int bitmapWidth = options.outWidth;
        int bitmapHeight = options.outHeight;
        int inWidthSampleSize = bitmapWidth / size.width;
        int inHeightSampleSize = 1;
        if (size.height != 0) {
            inHeightSampleSize = bitmapHeight / size.height;
            options.outHeight = size.height;
            options.inSampleSize = inWidthSampleSize > inHeightSampleSize ? inHeightSampleSize : inWidthSampleSize;
        } else {
            options.inSampleSize = inWidthSampleSize;
        }

        options.inJustDecodeBounds = false;
        int jiaodu = readPictureDegree(file.getAbsolutePath());
        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(filepath, null, options);
//		PalLog.d("pic", "create bitmap size="+bitmap.getWidth()+"*"+bitmap.getHeight());
        if (bitmap != null) {
            if (jiaodu != 0) {
                bitmap = rotaingImageView(jiaodu, bitmap);
            }
            if (bitmap.getHeight() != size.height || bitmap.getWidth() != size.width) {
                Matrix matrix = new Matrix();
                if (size.height != 0) {
                    matrix.postScale((float) size.width / (float) bitmap.getWidth(), (float) size.height / (float) bitmap.getHeight());
                } else {
                    if (bitmap.getWidth() == size.width) {
                        return bitmap;
                    } else {
                        matrix.postScale((float) size.width / (float) bitmap.getWidth(), (float) size.width / (float) bitmap.getWidth());
                    }
                }
//                Bitmap newbm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,
//                        true);
                Bitmap newbm = createBitmapCatchError(bitmap, matrix);
//                bitmap.recycle();
                return newbm;
            }
        }
        return bitmap;
    }

    private Bitmap createNoSizeBitmap(FileDescriptor fileDescriptor, File file) throws Exception {
        Bitmap bitmap = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inPurgeable = true;
        options.inInputShareable = true;
        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
        int screenWidth = ViewUtil.getScreenWidth(mContext);
        int screenHeight = ViewUtil.getScreenHeight(mContext);
        int jiaodu = readPictureDegree(file.getAbsolutePath());
        int i = 0;
        while (true) {
            if ((options.outWidth >> i <= screenWidth)
                    || (options.outHeight >> i <= screenHeight)) {
                options.inSampleSize = (int) Math.pow(2.0D, i);
                options.inJustDecodeBounds = false;
                if (jiaodu != 0) {
                    Bitmap midbitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
                    bitmap = rotaingImageView(jiaodu, midbitmap);
                    midbitmap.recycle();
                } else {
                    bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
                }
                break;
            }
            i += 1;
        }
        return bitmap;
    }

    private Bitmap createBitmapCatchError(Bitmap bitmap, Matrix matrix) {
        Bitmap newBitmap = null;
        if (bitmap != null) {
            try {
                newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
                return bitmap;
            }

            if (newBitmap == bitmap) {
                return bitmap;
            }

            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
            return newBitmap;
        }
        return bitmap;
    }

    public Bitmap rotaingImageView(int angle, Bitmap bitmap) {
        //旋转图片 动作
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        System.out.println("angle2=" + angle);
        // 创建新的图片
//        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
//                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//        bitmap.recycle();
        Bitmap resizedBitmap = createBitmapCatchError(bitmap, matrix);
        return resizedBitmap;
    }

    public int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    public interface ImageCallBack {

        public void onGetImage(Bitmap bitmap, String url);

        public void onGetError(String url);
    }

    public ExecutorService getThreadPool() {
        if (mImageThreadPool == null) {
            synchronized (ExecutorService.class) {
                if (mImageThreadPool == null) {
                    //为了下载图片更加的流畅，我们用了5个线程来下载图片
                    mImageThreadPool = Executors.newFixedThreadPool(5);
                }
            }
        }

        return mImageThreadPool;

    }

}
